package com.gzsxy.esjy.service.netty.service;

import com.gzsxy.esjy.response.NettyHttpResponse;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

/**
 * 文件
 * @author zhangxiaolong
 * @date 2022/7/11 9:36
 */
@Slf4j
public class PlayRunnable implements Runnable{

    private final File file ;

    private ChannelHandlerContext ctx;

    private final Channel channel ;

    private final boolean keepLive;

    private int range ;

    private Integer end ;

    /**
     * 默认分布 2M
     */
    private final static long part = 1024 *1024 * 2 ;


    public PlayRunnable(File aim, ChannelHandlerContext ctx, boolean keepAlive, String range) {
        this.file = aim ;
        this.ctx = ctx;
        this.channel = ctx.channel();
        this.keepLive = keepAlive;

        String replace = range.replace("bytes=", "");
        String[] split = replace.split("-");
        if(split.length >0){
            this.range = Integer.parseInt(split[0]);
        }
        if(split.length >1){
            this.end = Integer.parseInt(split[1]);
        }

    }

    @Override
    public void run() {
        try {
            service() ;
        }catch(Exception e) {
            ChannelFuture writeAndFlush = channel.writeAndFlush(NettyHttpResponse.doExceptionResponse(e, "utf-8"));
            if(!keepLive) {
                writeAndFlush.addListener(ChannelFutureListener.CLOSE);
            }
        }
    }

    /**
     * 业务
     * @throws Exception
     */
    private void service() throws Exception {
        //随机文件读写类
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r") ;
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);

        //获取文件长度
        long fileLength = randomAccessFile.length();
        //设置响应信息
        response.headers().add("Access-Control-Allow-Origin", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client");
        response.headers().add("Access-Control-Allow-Methods", "*");
        response.headers().add("Access-Control-Max-Age", "18000L");
        response.headers().add("Access-Control-Allow-Headers", "*");
        response.headers().add("Access-Control-Expose-Headers", "*");
        response.headers().add("Access-Control-Allow-Credentials", "true");
        //设置响应头
        setContentTypeHeader(response, file);

        //如果一直保持连接则设置响应头信息为：HttpHeaders.Values.KEEP_ALIVE
        if (!keepLive) {
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }

        int  startIndex = (int) range;

        int endIndex = (int) (startIndex + part - 1);

        //是否指定了索引终结点
        if (end != null){
            endIndex = end;
        }

        if (endIndex <= startIndex ){
            endIndex = (int) (startIndex + part - 1);
        }
        if (endIndex > fileLength - 1) {
            endIndex = (int) (fileLength - 1);
        }
        int len = endIndex - startIndex+1 ;

        response.headers().set(HttpHeaderNames.CONTENT_LENGTH,len) ;

//        Accept-Ranges: bytes
        response.headers().set(HttpHeaderNames.ACCEPT_RANGES,"bytes") ;
        response.setStatus(HttpResponseStatus.PARTIAL_CONTENT);
        response.headers().set(HttpHeaderNames.CONTENT_RANGE, "bytes " + range + "-" + (endIndex)+ "/" + fileLength);

        //进行写出
        downLoad(ctx, randomAccessFile, response, len);
    }

    /**
     * 文件下载
     * @param ctx
     * @param randomAccessFile
     * @param response
     * @param fileLength
     * @throws IOException
     */
    private void downLoad(ChannelHandlerContext ctx,RandomAccessFile randomAccessFile,
                          HttpResponse response, long fileLength) throws FileNotFoundException {
        channel.write(response) ;
        channel.write(new DefaultFileRegion(randomAccessFile.getChannel(), range, fileLength), channel.newProgressivePromise()) ;
        channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT).addListener(ChannelFutureListener.CLOSE);
    }

    private static void setContentTypeHeader(HttpResponse response, File file) {
        MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
    }

    public static void main(String[] args) {
        MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
        String ss = mimeTypesMap.getContentType("C:\\Users\\hezhiyuan\\Downloads\\A4406065506002018010023_何金旺_2021-05-12-15-26-59.mp4") ;
        System.out.println(ss);
    }
}
